#include <stdio.h>
#include <time.h>
#include <grp.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <error.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <dirent.h>

#define MAXPATH 128
#define MAXSIZE 4096

int get_list(const char *, char *, int);

int main()
{
	char buf[MAXSIZE];
	get_list("", buf, sizeof(buf));
	printf("%s\n", buf);
}

int get_list(const char *path, char *buf, int size)
{
	int timelen;
	char timebuf[64];
	struct tm *ptime;
	struct passwd *pwd;
	struct group *grp;
	int offsize = 0;
	char pathname[MAXPATH];
	char mode[12] = "-----------";
	DIR *dp;	
	struct dirent *dirp;
	struct stat lsstat;
	struct stat pathstat;

	strcpy(pathname, path);
	if (strcmp(pathname,"") == 0) { // list current dir
		if (getcwd(pathname, MAXPATH) == NULL) {
			fprintf(stderr, "getcwd in get_list error!\n");	
			return (-1);
		}
	}
	if (lstat(pathname, &pathstat) < 0) { // get cmdline type, dir or regular file
		fprintf(stderr, "lstat in get_list error!\n");	
		return (-1);
	}
	if (S_ISDIR(pathstat.st_mode)) { // dir
		if ((dp = opendir(pathname)) == NULL) {
			fprintf(stderr, "opendir error!\n");	
			closedir(dp);
			return (-1);
		}
		offsize = 0;
		while ((dirp = readdir(dp)) != NULL) {
			for (int i = 0; i < 11; i++) 
				mode[i] = '-';	

			if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)	
				continue;
			if (lstat(dirp->d_name, &lsstat) < 0) {
				fprintf(stderr, "lstat in get_list error!\n");	
				return (-1);
			}
			if (S_ISDIR(lsstat.st_mode)) // dir 
				mode[0] = 'd';		
			if (S_ISREG(lsstat.st_mode))  // regular file
				mode[0] = '-';
			// access permission and nlinks
			if  (S_IRUSR &lsstat.st_mode)	
				mode[1] = 'r';
			if  (S_IWUSR &lsstat.st_mode)	
				mode[2] = 'w';
			if  (S_IXUSR &lsstat.st_mode)	
				mode[3] = 'x';
			if  (S_IRGRP &lsstat.st_mode)	
				mode[4] = 'r';
			if  (S_IWGRP &lsstat.st_mode)	
				mode[5] = 'w';
			if  (S_IXGRP &lsstat.st_mode)	
				mode[6] = 'x';
			if  (S_IROTH &lsstat.st_mode)	
				mode[7] = 'r';
			if  (S_IWOTH &lsstat.st_mode)	
				mode[8] = 'w';
			if  (S_IXOTH &lsstat.st_mode)	
				mode[9] = 'x';
			mode[10] = '\0';
			offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s  %d  ", mode, lsstat.st_nlink);
			// user
			if ((pwd = getpwuid(lsstat.st_uid)) == NULL) {
				fprintf(stderr, "getpwuid error in get_list!\n");	
				return (-1);
			}
			offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", pwd->pw_name);
			// group
			if ((grp = getgrgid(lsstat.st_gid)) == NULL) {
				fprintf(stderr, "getpwuid error in get_list!\n");	
				return (-1);
			}
			offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", grp->gr_name);
			// size
			offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%*d ", 10,  lsstat.st_size);
			// mtime 
			ptime = localtime(&(lsstat.st_mtime));
			if (ptime && (timelen = strftime(timebuf, sizeof(timebuf), "%b %d %H:%S", ptime)) > 0) {
				timebuf[timelen] = '\0';	
				offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", timebuf);
			} else {
				fprintf(stderr, "strftime error in get_list!\n");	
				return (-1);
			}

			offsize += snprintf(buf + offsize, MAXSIZE-offsize, "%s\r\n", dirp->d_name);		
		}		
	}
	
	
	if (S_ISREG(pathstat.st_mode)) { // regular file
		offsize = 0;
		// access permission and nlinks
		if  (S_IRUSR &lsstat.st_mode)	
			mode[1] = 'r';
		if  (S_IWUSR &lsstat.st_mode)	
			mode[2] = 'w';
		if  (S_IXUSR &lsstat.st_mode)	
			mode[3] = 'x';
		if  (S_IRGRP &lsstat.st_mode)	
			mode[4] = 'r';
		if  (S_IWGRP &lsstat.st_mode)	
			mode[5] = 'w';
		if  (S_IXGRP &lsstat.st_mode)	
			mode[6] = 'x';
		if  (S_IROTH &lsstat.st_mode)	
			mode[7] = 'r';
		if  (S_IWOTH &lsstat.st_mode)	
			mode[8] = 'w';
		if  (S_IXOTH &lsstat.st_mode)	
			mode[9] = 'x';
		mode[10] = '\0';
		offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s  %d  ", mode, lsstat.st_nlink);
		// user
		if ((pwd = getpwuid(lsstat.st_uid)) == NULL) {
			fprintf(stderr, "getpwuid error in get_list!\n");	
			return (-1);
		}
		offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", pwd->pw_name);
		// group
		if ((grp = getgrgid(lsstat.st_gid)) == NULL) {
			fprintf(stderr, "getpwuid error in get_list!\n");	
			return (-1);
		}
		offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", grp->gr_name);
		// size
		offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%*d ", 10,  lsstat.st_size);
		// mtime 
		ptime = localtime(&(lsstat.st_mtime));
		if (ptime && (timelen = strftime(timebuf, sizeof(timebuf), "%b %d %H:%S", ptime)) > 0) {
		timebuf[timelen] = '\0';	
		offsize += snprintf(buf+offsize, MAXSIZE-offsize, "%s ", timebuf);
		} else {
			fprintf(stderr, "strftime error in get_list!\n");	
			return (-1);
		}

		offsize += snprintf(buf + offsize, MAXSIZE-offsize, "%s\r\n", pathname);
	}

	return offsize;
}
